﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using ColorClusteringSOM.Util;
using ColorClusteringSOM.Evaluation;

namespace ColorClusteringSOM
{
    class Program
    {
        //********************TRAINING********************
        //************************************************
        TrainNetwork training = null;

        int epoch = 500;

        double learningRate = 0.5; //uceni

        //okoli neuronu neboli radius urcuje se podle dimenze mrizky...bere se ta vetsi hodnota napr
        //10x10 = 100 neuronu takze radius je 10
        double neighbourhoodRadius = 10;

        //pocet vystupnich neuronu (vytvori ctvercovou matici napr 30x30) 
        int outputNeurons = 10;

        //pocet vstupnich neuronu
        int inputNeurons =41;

        // neuronova sit
        Network network = null;

        //********************CLASSIFICATION**************
        //************************************************

        Classification classification = null;

        //********************CLUSTERING******************
        //************************************************

        ClusterNetwork clustering = null;


        List<int[]> list8 = null;

        String[] namesSmallSOM =
        {"DOS1000epoch0,2LearnRate25Neurons.bin",
"DOS1000epoch0,2LearnRate49Neurons.bin",
"DOS1000epoch0,5LearnRate25Neurons.bin",
"DOS1000epoch0,5LearnRate49Neurons.bin",
"DOS200epoch0,2LearnRate25Neurons.bin",
"DOS200epoch0,2LearnRate49Neurons.bin",
"DOS200epoch0,5LearnRate25Neurons.bin",
"DOS200epoch0,5LearnRate49Neurons.bin",
"DOS500epoch0,2LearnRate25Neurons.bin",
"DOS500epoch0,2LearnRate49Neurons.bin",
"DOS500epoch0,5LearnRate25Neurons.bin",
"DOS500epoch0,5LearnRate49Neurons.bin",
        };

        String[] namesBigSOM = {"DOS1000epoch0,2LearnRate100Neurons.bin",
"DOS1000epoch0,2LearnRate196Neurons.bin",
"DOS1000epoch0,5LearnRate100Neurons.bin",
"DOS1000epoch0,5LearnRate196Neurons.bin",
"DOS200epoch0,2LearnRate100Neurons.bin",
"DOS200epoch0,2LearnRate196Neurons.bin",
"DOS200epoch0,5LearnRate100Neurons.bin",
"DOS200epoch0,5LearnRate196Neurons.bin",
"DOS500epoch0,2LearnRate100Neurons.bin",
"DOS500epoch0,2LearnRate196Neurons.bin",
"DOS500epoch0,5LearnRate100Neurons.bin",
"DOS500epoch0,5LearnRate196Neurons.bin",

                             };

        static void Main()
        {
            Program p = new Program();
            //p.StartTrainingSom();
            //p.StartVisualization();
            //p.SimpleClassification();
            //p.StartSimpleClassification();
            //p.StartClustering();
            //p.StartVisualization();
            //Reader.ListOfColors("HtmlBarvy.txt");
            //p.GeneratingSOMs();

            //p.TestingValidation();
            //p.TestingSomValidationData();
            //p.testFidler();

            //p.TestRGB();
            //p.TestingSomValidationData();
            //p.TestKmeans();
            p.TestingRoughSet();
        }

        public void TestRGB()
        {
            string slozka = "rgb";
            string logName = "logRGB";

            int[] pocetVystupnichNer = { 10 }; //pocty vystupnich neuronu 25,49,100,196
            double[] learningRates = { 0.5};
            int[] epochy = { 5000 };


            //double[,] matrixData = Reader.IntruderReader("DOSClass 3.train");

            for (int i = 0; i < pocetVystupnichNer.Length; i++)
            {
                for (int j = 0; j < learningRates.Length; j++)
                {
                    for (int e = 0; e < epochy.Length; e++)
                    {

                        //network = new Network(3, pocetVystupnichNer[i]);
                        //training = new TrainNetwork(network, epochy[e], learningRates[j], pocetVystupnichNer[i]);
                        //training.Train();

                        String name = "RGB" + epochy[e] + "epoch" + learningRates[j] + "LearnRate" + pocetVystupnichNer[i] * pocetVystupnichNer[i] + "Neurons";
                        
                        ////Writer.WriteTrainedSom(network, slozka+"\\"+name);
                        network = Writer.ReadTrainedSom(slozka + "\\" + name);

                        int countClusters = 5;
                        double w_lower = 0.9;
                        double w_upper = 0.1;
                        double threshold = 0.2;

                        name += " cluster=" + countClusters + " w_lower=" + w_lower + " w_uppew=" + w_upper + " threshold=" + threshold;

                        clustering = new ClusterNetwork(network, threshold, w_lower, w_upper);
                        clustering.KmeansRoughSet(countClusters);

                        
                        FukuyamaSugeno fuku = new FukuyamaSugeno(clustering.Leaders, 2);
                        double fukuIndex = fuku.FukuyamaSugenoIndex();

                        XieBeni xie = new XieBeni(clustering.Leaders);
                        double xieIndex = xie.XieBeniIndex();

                        name += " FukuIndex="+fukuIndex + " XieBeniIndex="+xieIndex;
                        Console.WriteLine("FukuyamaSugeno Index = " + fukuIndex);
                        Console.WriteLine("XieBeni Index = " + xieIndex);

                        Writer.CreateLog(logName,name);

                       Application.EnableVisualStyles();
                       //Application.SetCompatibleTextRenderingDefault(true);
                       Application.Run(new Visualization(network, clustering.Leaders, slozka + "\\" + name, ""));

                        
                      
                    }
                }

            }

          



        }

        public void SomValidationData()
        {

            String[] names = {"DOS1000epoch0,2LearnRate100Neurons.bin",
"DOS1000epoch0,2LearnRate196Neurons.bin",
"DOS1000epoch0,2LearnRate25Neurons.bin",
"DOS1000epoch0,2LearnRate49Neurons.bin",
"DOS1000epoch0,5LearnRate100Neurons.bin",
"DOS1000epoch0,5LearnRate196Neurons.bin",
"DOS1000epoch0,5LearnRate25Neurons.bin",
"DOS1000epoch0,5LearnRate49Neurons.bin",
"DOS200epoch0,2LearnRate100Neurons.bin",
"DOS200epoch0,2LearnRate196Neurons.bin",
"DOS200epoch0,2LearnRate25Neurons.bin",
"DOS200epoch0,2LearnRate49Neurons.bin",
"DOS200epoch0,5LearnRate100Neurons.bin",
"DOS200epoch0,5LearnRate196Neurons.bin",
"DOS200epoch0,5LearnRate25Neurons.bin",
"DOS200epoch0,5LearnRate49Neurons.bin",
"DOS500epoch0,2LearnRate100Neurons.bin",
"DOS500epoch0,2LearnRate196Neurons.bin",
"DOS500epoch0,2LearnRate25Neurons.bin",
"DOS500epoch0,2LearnRate49Neurons.bin",
"DOS500epoch0,5LearnRate100Neurons.bin",
"DOS500epoch0,5LearnRate196Neurons.bin",
"DOS500epoch0,5LearnRate25Neurons.bin",
"DOS500epoch0,5LearnRate49Neurons.bin",
                             };
             
            for (int s = 0; s < names.Length; s++)
            {


            network = Writer.ReadTrainedSom(names[s]);//"DOS2000epoch0,1LearnRate100Neurons"
            Classification cl = new Classification(network);

            Network clasNetwork = cl.FIRSTClassificateIntruders("testcl3.txt");
            String matice = "";
            //for (int i = 0; i < clasNetwork.Rows; i++)
            //{
            //    for (int j = 0; j < clasNetwork.Cols; j++)
            //    {
    
            //        //Console.Write(" "+clasNetwork[i,j].NeuronType);
            //        matice += " "+clasNetwork[i,j].NeuronType;
            //    }
            //   // Console.Write("\n");
            //    matice += "\n";
                
            //}

            String str = "\n"+names[s]; 
            str += cl.SECONDClassificateIntruders("testcl3.txt");
            str += matice+"\n";
           
            Console.WriteLine(str);
            Writer.CreateLog("somTATA", str);
            }
        }



       

        public void Kmeans()
        {

            String[] names = namesBigSOM; // kolekce siti
            int step = 5; // krok pocet center
            int maxK = 30; // maximalni pocet center



            //String name = "DOS1000epoch0,2LearnRate196Neurons.bin";

            for (int s = 0; s < names.Length; s++)
            {

                network = Writer.ReadTrainedSom(names[s]); // nacteme naucenou sit

                Classification ss = new Classification(network); //
                Network clasNetwork = ss.FIRSTClassificateIntruders("testcl3.txt"); // provadi se klasifikace jen somky


                ClusterNetwork cl = new ClusterNetwork(clasNetwork); // pozije se klasifikovana sit

                for (int k = 5; k <= maxK; k+=step)
                {
                    
               
                cl.Kmeans(k); // kmeans

                // Jsou tedka utvorene shluky a musi se rozhodnout co reprezentuji

                String attack = "A";
                String nonAttack = "N";

                foreach (NeuronRough center in cl.Leaders)
                {
                    int counter = 0;
                    foreach (NeuronRough neuron in center.LowerAppNeuronsArray)
                    {
                        counter += neuron.Neuron.AttackCounter();

                    }
                    Console.WriteLine(counter);
                    if (counter > 0) // pokud bylo vice utoku, pak shluk je utok
                    {
                        center.LeaderName = attack;
                    }
                    else if (counter < 0) // jinak neni
                    {
                        center.LeaderName = nonAttack;
                    }
                    else
                    {
                        center.LeaderName = "X";
                    }

                    counter = 0;


                }


                double[,] valMatrix = Reader.IntruderValidationReader("testcl3.txt"); // validacni sit
                String str = "\n"+names[s];
                str += " " +k;
                str += ss.SECONDClassificateIntrudersKMEANS("testcl3.txt", cl.Leaders);
                str += "\n";
                Console.WriteLine(str);
                Writer.CreateLog("KmeansVELKE", str);
                }

            }


        }


        public void TestingRoughSet()
        {
            String[] namesForRoughSMALL = {"DOS1000epoch0,2LearnRate25Neurons.bin",
                                          "DOS200epoch0,5LearnRate25Neurons.bin",
                                          "DOS1000epoch0,2LearnRate49Neurons.bin",
                                          "DOS500epoch0,5LearnRate49Neurons.bin"
                                 };


            String[] names = namesForRoughSMALL; // kolekce siti
            int step = 1; // krok pocet center
            int maxK = 5; // maximalni pocet center

            int countClusters = 8;
            double w_lower = 0.9;
            double w_upper = 0.1;
            double threshold = 0.2;

            String name = "DOS500epoch0,2LearnRate196Neurons.bin";
           
            Writer.CreateLog("RoughSet", "\n"+name + "\tThreshold=" + threshold + "\tW_lower=" + w_lower + "\tW_upper=" + w_upper );
             



             for (int s = 0; s < 5; s++)
            {
            
            network = Writer.ReadTrainedSom(name);

           
            Classification ss = new Classification(network); //
            Network clasNetwork = ss.FIRSTClassificateIntruders("testcl3.txt"); // provadi se klasifikace jen somky
            // tady je somka uz i ohodnocena


       
            
            clustering = new ClusterNetwork(clasNetwork, threshold, w_lower, w_upper);

           
            //clustering.Leaders;

            //for (int k = 3; k <= maxK; k += step)
            //{
            String settings = "\nClusters=" + countClusters + "\nw_lower=" + w_lower + "\nw_upper=" + w_upper + "\nthreshold=" + threshold;

            clustering.KmeansRoughSet(countClusters);


                // Jsou tedka utvorene shluky a musi se rozhodnout co reprezentuji

                String attack = "A";    // slouzi pro oznaceni jestli dolni aproximace shluku je utok
                String nonAttack = "N";  // nebo bezny provoz

                foreach (NeuronRough center in clustering.Leaders)
                {
                    int counter = 0;
                    foreach (NeuronRough neuron in center.LowerAppNeuronsArray) // tedy berou se v potaz jen neurony v dolnich aproximacich
                    {
                        counter += neuron.Neuron.AttackCounter();

                    }
                    //Console.WriteLine("COUNTER="+counter);

                    if (counter > 0) // pokud bylo vice utoku, pak shluk je utok
                    {
                        center.LeaderName = attack;
                       
                       
                    }
                    else if (counter < 0) // jinak neni
                    {
                        center.LeaderName = nonAttack;

                    }
                    else
                    {
                        center.LeaderName = "X";
                    }
                   
                    

                    counter = 0;


                }

                double[,] valMatrix = Reader.IntruderValidationReader("testcl3.txt"); // validacni sit
                String str = " " + countClusters;
                 str += ss.SECONDClassificateIntrudersROUGH("testcl3.txt", clustering.Leaders);
                //str += "\n";
                Console.WriteLine(str);
               Writer.CreateLog("RoughSet", str);
            }


            //Writer.CreateLog("IndexSOM", "\n" + name + settings + "\nFuku=" + fukuIndex + "\nXie=" + xieIndex);
            //Application.EnableVisualStyles();
            //Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Visualization(network, clustering.Leaders, ""));
           

            

            PrintClustersValues(clustering.Leaders);

            
         }



        public void GeneratingSOMs()
        {
            int[] pocetVystupnichNer = { 5, 7, 10, 14, 18 }; //pocty vystupnich neuronu 25,49,100,196,324
            double[] learningRates = { 0.1, 0.2, 0.5 };
            int[] epochy = { 200, 500, 1000, 2000 };

            Fidler f = new Fidler();

            double[,] matrixData = Reader.IntruderReader("DOSClass 3.train");

            for (int i = 0; i < pocetVystupnichNer.Length; i++)
            {
                for (int j = 0; j < learningRates.Length; j++)
                {
                    for (int e = 0; e < epochy.Length; e++)
                    {

                        network = new Network(InputNeurons, pocetVystupnichNer[i]);
                        training = new TrainNetwork(network, epochy[e], learningRates[j], pocetVystupnichNer[i]);
                        String name = "DOS" + epochy[e] + "epoch" + learningRates[j] + "LearnRate" + pocetVystupnichNer[i] * pocetVystupnichNer[i] + "Neurons";
                        Console.WriteLine(name);
                        training.Train2(matrixData, 5092, 41);


                        Writer.WriteTrainedSom(network, name);
                        f.FidlerOutput(network, name);

                    }
                }

            }

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Visualization(network, null, "", ""));

        }

        public void Fidler()
        {
            //////network = Writer.ReadTrainedSom("500epoch03learninNOCNITEST train2");
            double[,] matrixData = Reader.IntruderReader("DOSClass 3.train");

            network = new Network(InputNeurons, 5);
            training = new TrainNetwork(Network, 5, learningRate, 5);
            training.Train2(matrixData, 5092, 41);

            //network = new Network(3, 5);
            //training = new TrainNetwork(network, 1000, learningRate, 5);
            //training.Train();

            Fidler f = new Fidler();
            f.FidlerOutput(network, "TESTFIDLER_Fidler");
        }
        public void PrintClustersValues(List<NeuronRough> clusters)
        {
            String s = String.Empty;
            int count = 0;
            foreach (NeuronRough leader in clusters)
            {
                s += "\nCislo shluku" + count;
                count++;
                s+="\nLower="+leader.LowerAppNeuronsArray.Count+"\n";
                s+="Upper="+leader.UpperAppNeuronsArray.Count+"\n";

                int cLow = 0;
                foreach (NeuronRough lowApp in leader.LowerAppNeuronsArray)
                {

                    s += lowApp.Neuron.NeuronType+ ":"+lowApp.Neuron.AttackCounter() + " , ";
                    cLow += lowApp.Neuron.AttackCounter();

                }
                s += "  sum=" +cLow+ "\n";
                cLow = 0;
                foreach (NeuronRough uppApp in leader.UpperAppNeuronsArray)
                {
                    s += uppApp.Neuron.NeuronType + ":" + uppApp.Neuron.AttackCounter() + " , ";
                    cLow += uppApp.Neuron.AttackCounter();
                }
                s += "  sum=" + cLow + "\n";
                cLow = 0;
                Console.WriteLine(s);
                s = String.Empty;
            }
        }


        /// <summary>
        ///
        /// </summary>
        public void StartClustering()
        {
            //Sit_pocetNeuronu.bin epoch_1000_fidler.txt
            //String name = "sit_test";

            String name = "500epoch03learninNOCNITEST train2";

            //double[,] matrixData = Reader.DataMatrix("medlarDATA.txt");

            double[,] matrixData = Reader.IntruderReader("DOSClass 3.train");

            network = new Network(InputNeurons, outputNeurons);
            training = new TrainNetwork(Network, epoch, learningRate, neighbourhoodRadius);
            training.Train2(matrixData, 5092, 41);

            Writer.WriteTrainedSom(network, name);

            
            
            
            Fidler f = new Fidler();
            f.FidlerOutput(network, name + "_Fidler");

            int countClusters = 5;
            double w_lower = 0.65;
            double w_upper = 0.35;
            double threshold = 0.3;

            clustering = new ClusterNetwork(network, threshold, w_lower, w_upper);
            clustering.KmeansRoughSet(countClusters);

            FukuyamaSugeno fuku = new FukuyamaSugeno(clustering.Leaders, 2);
            double fukuIndex = fuku.FukuyamaSugenoIndex();

            XieBeni xie = new XieBeni(clustering.Leaders);
            double xieIndex = xie.XieBeniIndex();

            Console.WriteLine("FukuyamaSugeno Index = " + fukuIndex);
            Console.WriteLine("XieBeni Index = " + xieIndex);



            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Visualization(network, null,"", ""));

            //////training
            //network = new Network(InputNeurons, outputNeurons);
            //training = new TrainNetwork(Network, epoch, learningRate, neighbourhoodRadius);
            //training.Train();


            //Application.EnableVisualStyles();
            //Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Visualization(network));

            //////saving network
           // Writer.WriteTrainedSom(network, name);

           // //loading
            //network = Writer.ReadTrainedSom(name);

          
            
            //clustering

            //////***K-means***
            //clustering = new ClusterNetwork(network);
            //clustering.Kmeans(5);


            ////// ***K-means a Rough sets***
            ////// w_lower + w_upper = 1 !!!
            //int countClusters = 3;
            //double w_lower = 0.75;
            //double w_upper = 0.25;
            //double threshold = 0.1;

            String info = "";//"\nPočet clutrů="+countClusters+"\nW_Lower="+w_lower+"\nW_Upper="+w_upper+"\nThreshold="+threshold+"\n";
            ////Console.WriteLine("\nPocet clutru={0}\nW_Lower={1}\nW_Upper={2}\nThreshold={3}\n", countClusters, w_lower, w_upper, threshold);
            //clustering = new ClusterNetwork(network, w_lower, w_upper, threshold);
            //clustering.KmeansRoughSet(countClusters);

            

           //// ////Visualization

           //Application.EnableVisualStyles();
           //Application.SetCompatibleTextRenderingDefault(false);
           //Application.Run(new Visualization(network, clustering.Leaders, info));
           
        }


        /// <summary>
        /// Spusteci metoda, ktera vykresli natrenovanou sit (ci sit po clusteringu -dodela se)
        /// </summary>
        public void StartVisualization()
        {
            String[] info = { "" };
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
         //   Application.Run(new Visualization(Network, winners));
        }

        /// <summary>
        /// Spusteci metoda, ktera natrenouje neuronovou sit
        /// </summary>
        public void StartTrainingSom()
        {
            //Writer writer = new Writer();

            // vytvoreni site 3 vstupni neurony, 10x10 vystupni sit
            network = new Network(InputNeurons, outputNeurons);

            // writer.WriteMatrix("randomSOM", Network, outputNeurons, outputNeurons);

            training = new TrainNetwork(Network, epoch, learningRate, neighbourhoodRadius);
            training.Train();

            // writer.WriteMatrix("NatrenovanySOM", Network, outputNeurons, outputNeurons);
        }

        /// <summary>
        /// Jenom pro testy
        /// </summary>
        /// <returns></returns>
        public List<int[]> Data()
        {
            list8 = new List<int[]>();
            //list8.Add(new int[] { 255, 0, 0 });   // Red
            //list8.Add(new int[] { 0, 128, 0 });   // Green
            //list8.Add(new int[] { 0, 0, 255 });   // Blue
            //list8.Add(new int[] { 0, 100, 0 });   // Dark green
            //list8.Add(new int[] { 0, 0, 139 });   // Dark blue
            //list8.Add(new int[] { 255, 255, 0 });   // Yellow
            //list8.Add(new int[] { 255, 165, 0 });   // Orange
            //list8.Add(new int[] { 128, 0, 128 });   // Purple

            Random rnd = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < 15; i++)
            {
                list8.Add(new int[] { rnd.Next(255), rnd.Next(255), rnd.Next(255) });
            }

            

            return list8;
        }
        /// <summary>
        /// Klasifikace uz vetsiho vstupu nejakych hodnoto
        /// </summary>
        public void StartSimpleClassification()
        {
            classification = new Classification(network);
            classification.SimpleClassification(Data());

        }


        /// <summary>
        /// Jednoducha klasifikace, kde je na vstupu jen jeden vzorek
        /// tedy vrati vitezny neuron
        /// </summary>
        public void ClassificationWithOneEntry()
        {
            classification = new Classification(network);
            int[] data = new int[] { 0, 0, 255 };   // Blue
            Neuron ner = classification.WinnerOfClassification(data);

            int R = (int)(ner.Weights[0] * 255);
            int G = (int)(ner.Weights[1] * 255);
            int B = (int)(ner.Weights[2] * 255);

            Console.WriteLine(" 0, 0, 255 });   Blue" + ner.ToString() + "\n R=" + R + " G=" + G + " B=" + B);

        }

      

        #region Properties

        public Network Network
        {
            get { return this.network; }
        }

        public int Epoch
        {
            get { return this.epoch; }
        }

        public double LearningRate
        {
            get { return this.learningRate; }
        }

        public int OutputNeurons
        {
            get { return this.outputNeurons; }
        }

        public double NeighbourhoodRadius
        {
            get { return this.neighbourhoodRadius; }
        }

        public int InputNeurons
        {
            get { return this.inputNeurons; }
        }
        #endregion
    }
}
